package codec

import (
	"fmt"
	"gitee.com/visons/gopkg/net/ws"
	"github.com/golang/protobuf/proto"
	"github.com/gorilla/websocket"
	"reflect"
	"time"
)

//协议定义需要只解析单种类型的消息
type pbCodec struct {
	conn     *websocket.Conn
	protocol *pbProtocol
}

func (self *pbCodec) Send(msg interface{}) error {
	bytes, err := proto.Marshal(msg.(proto.Message))
	if err != nil {
		return err
	}
	if self.protocol.writeTimeout != 0 {
		self.conn.SetWriteDeadline(time.Now().Add(self.protocol.writeTimeout))
	}
	return self.conn.WriteMessage(websocket.BinaryMessage, bytes)
}

func (self *pbCodec) Receive() (interface{}, error) {

	if self.protocol.readiTimeout != 0 {
		self.conn.SetReadDeadline(time.Now().Add(self.protocol.readiTimeout))
	}
	t, msg, err := self.conn.ReadMessage()
	if err != nil {
		return nil, err
	}
	if t != websocket.BinaryMessage {
		return nil, fmt.Errorf("websocket message must binary")
	}
	pbmsg := reflect.New(self.protocol.pbType).Interface().(proto.Message)
	err = proto.Unmarshal(msg, pbmsg)
	if err != nil {
		return nil, err
	}
	return pbmsg, err
}

func (self *pbCodec) Close() error {
	return self.conn.Close()
}

type pbProtocol struct {
	pbType       reflect.Type
	readiTimeout time.Duration
	writeTimeout time.Duration
}

func (self *pbProtocol) NewCodec(conn *websocket.Conn) (ws.Codec, error) {
	return &pbCodec{
		conn:     conn,
		protocol: self,
	}, nil
}

func Pb(pb proto.Message) *pbProtocol {
	return &pbProtocol{pbType: reflect.TypeOf(pb).Elem()}
}

func PbWithTimout(pb proto.Message, readTimout, writeTimout time.Duration) *pbProtocol {
	return &pbProtocol{pbType: reflect.TypeOf(pb).Elem(), readiTimeout: readTimout, writeTimeout: writeTimout}
}
